package com.alibaba.citrus.cr.mn.order.center.facade.function.common;

import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderLineWriteRepository;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderQueryServiceRepository;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderWriteRepository;
import com.alibaba.citrus.cr.common.constant.OrderFeaturesKey;
import com.alibaba.citrus.cr.common.enums.ordercenter.DictionaryTypeEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.InnerMessageEventEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.OrderCategoryEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.SalesOrderCloseEnum;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.mn.order.center.common.util.AssertUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.StopWatchUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BusinessUnitAbilityAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.DictionaryVerifyAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.function.check.CommonCheck;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.fastjson.JSON;
import com.epoch.app.crb2btradecenter.domain.order.dto.QueryByOrderBizIdsRequest;
import com.epoch.app.crb2btradecenter.enums.OrderStatus;
import com.epoch.app.crb2btradecenter.sdo.OrderLineSDO;
import com.epoch.app.crb2btradecenter.sdo.OrderSDO;
import com.epoch.app.mnordercenter.model.dto.Modifiers;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomBatchCancelRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomCancelRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomCancelResponse;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Chen.mu
 * 2023/5/11
 **/
public abstract class AbstractOrderAtomCancelService implements OrderAtomCancelService {
    private static final Log log = Log.getLogger(AbstractOrderAtomCancelService.class);

    @Resource
    private SendMsgService sendMsgService;
    @Resource
    private OrderQueryServiceRepository orderQueryServiceRepository;
    @Resource
    private OrderWriteRepository orderWriteRepository;
    @Resource
    private OrderLineWriteRepository orderLineWriteRepository;
    @Resource
    private DictionaryVerifyAdapter dictionaryVerifyAdapter;
    @Resource
    private BusinessUnitAbilityAdapter businessUnitAbilityAdapter;
    @Resource
    private CommonCheck commonCheck;

    /**允许取消的单据状态**/
    private static final EnumSet<OrderStatus> CAN_CANCEL_ORDER_STATUS = EnumSet.of(
            OrderStatus.BEFORE_SUBMIT,
            OrderStatus.STAY_PUSH);

    public abstract String getOrderTypeName();

    /**
     * 返回 销售 退货 换货Tag
     *
     * @return
     */
    protected abstract String getOrderTag();

    @Override
    public List<OrderAtomCancelResponse> batchCancel(OrderAtomBatchCancelRequest request) {
        return batchCancel(request, OrderCategoryEnum.COMPANY.getCode());
    }

    @Override
    public List<OrderAtomCancelResponse> batchCancel(OrderAtomBatchCancelRequest request, String orderCategory) {
        StopWatch stopWatch = new StopWatch("batchCancel");

        // 参数预处理
        stopWatch.start("preHandleRequestParams");
        preHandleRequestParams(request, orderCategory);
        stopWatch.stop();

        // 参数校验
        stopWatch.start("paramsInvalidCheck");
        paramsInvalidCheck(request, orderCategory);
        stopWatch.stop();

        // 参数补全
        stopWatch.start("assembleBizBaseInfo");
        assembleBizBaseInfo(request, orderCategory);
        stopWatch.stop();

        stopWatch.start("querySalesOrder");
        List<OrderAtomCancelResponse> responseList = new ArrayList<>();
        List<OrderSDO> orderSDOS = querySalesOrder(request, responseList, true);
        stopWatch.stop();
        if (CollectionUtils.isEmpty(orderSDOS)) {
            return responseList;
        }

        Map<String, OrderAtomCancelRequest> requestHashMap = request.getOrderList().stream()
                .collect(Collectors.toMap(k -> String.format("%s_%s_%s_%s", request.getFromSys(), request.getBusinessType(), request.getBusinessUnitCode(), k.getSalesOrderNo()), x -> x, (a, b) -> a));

        Map<String, List<String>> orderIdsMap = new HashMap<>();
        String modifierCode = "";
        String modifierName = "";
        // 取出占用了活动的预报订单明细ID，用于释放活动预占
        Map<String, List<String>> forecastOrderLineIdsMap = new HashMap<>();
        for (OrderSDO orderSDO : orderSDOS) {
            OrderAtomCancelResponse response = new OrderAtomCancelResponse();
            response.setSalesOrderNo(orderSDO.getOrderBizId());
            response.setSuccess(true);
            responseList.add(response);

            if (CAN_CANCEL_ORDER_STATUS.stream().noneMatch(p -> p.getCode().equals(orderSDO.getStatus()))) {
                ErrorMessage errorMessage = ErrorMessage.code("OC-01-001-01-16-053");
                response.setMessage(errorMessage.getDisplayErrorMessage());
                response.setErrorCode(errorMessage.getErrorCode());
                response.setSuccess(false);
                continue;
            }

            // 取出预报订单明细ID，用于释放活动预占
            if (Objects.nonNull(orderSDO.getFeatures()) && orderSDO.getFeatures().containsKey(OrderFeaturesKey.ACTIVITY_SEQUENCE_NO)) {
                String sequenceNo = orderSDO.getFeatures().get(OrderFeaturesKey.ACTIVITY_SEQUENCE_NO);
                if (!forecastOrderLineIdsMap.containsKey(sequenceNo)) {
                    forecastOrderLineIdsMap.put(sequenceNo, Lists.newArrayList());
                }
                for (OrderLineSDO orderLineSDO : orderSDO.getOrderLineSDOS()) {
                    // 记录需要释放活动的预报单明细ID
                    if (Objects.nonNull(orderLineSDO.getFeatures())) {
                        String forecastOrderLineId = orderLineSDO.getFeatures().get(OrderFeaturesKey.FORECAST_ORDER_LINE_ID);
                        if (StringUtils.isNotBlank(forecastOrderLineId)) {
                            List<String> forecastOrderLineIds = forecastOrderLineIdsMap.get(sequenceNo);
                            forecastOrderLineIds.add(forecastOrderLineId);
                            forecastOrderLineIdsMap.put(sequenceNo, forecastOrderLineIds);
                        }
                    }
                }
            }

            OrderAtomCancelRequest orderAtomCancelRequest = requestHashMap.get(String.format("%s_%s_%s_%s", orderSDO.getFromSys(), orderSDO.getBusinessType(), orderSDO.getBusinessUnitOutCode(), orderSDO.getOrderBizId()));
            modifierCode = orderAtomCancelRequest.getModifierCode();
            modifierName = orderAtomCancelRequest.getModifierName();

            // 根据关闭原因分组进行关闭
            String cancelCode = Optional.ofNullable(orderAtomCancelRequest.getCancelCode()).orElse("");
            List<String> tempOrderIds;
            if (orderIdsMap.containsKey(cancelCode)) {
                tempOrderIds = orderIdsMap.get(cancelCode);
            } else {
                tempOrderIds = new ArrayList<>();
            }
            tempOrderIds.add(orderSDO.getOrderBizId());
            if (OrderCategoryEnum.STOCK.getCode().equals(orderCategory) && StringUtils.isNotBlank(orderSDO.getRelationNo())) {
                // F1-B-b订单，同步取消F-B订单
                tempOrderIds.add(orderSDO.getRelationNo());
            }
            orderIdsMap.put(cancelCode, tempOrderIds);
        }

        for (Map.Entry<String, List<String>> entry : orderIdsMap.entrySet()) {
            String cancelCode = entry.getKey();
            List<String> orderBizIds = entry.getValue();

            stopWatch.start("batchCancelOrderLine");
            orderLineWriteRepository.batchCancel(modifierCode, modifierName, cancelCode, orderBizIds);
            stopWatch.stop();

            stopWatch.start("batchCancelOrder");
            orderWriteRepository.batchCancel(modifierCode, modifierName, cancelCode, orderBizIds);
            stopWatch.stop();
        }

        if (OrderCategoryEnum.COMPANY.getCode().equals(orderCategory)) {
            stopWatch.start("sendMsgToInventoryRelease");
            List<OrderSDO> sapCancelRequests = new ArrayList<>();
            orderSDOS.forEach(orderSDO -> {
                //B-b销售订单取消API-原子，默认设置拒绝原因"Z1";
                Optional.ofNullable(orderSDO.getOrderLineSDOS()).orElse(Lists.newArrayList()).forEach(orderLineSDO -> {
                    orderLineSDO.setRefuseReasonCode(SalesOrderCloseEnum.SALES_COMPANY_CLOSE_ITEM.getCode());
                });
                sapCancelRequests.add(orderSDO);
            });
            // 发送释放库存消息
            sendMsgService.sendMsgToInventoryRelease(sapCancelRequests);
            stopWatch.stop();
        }

        // 发送MQ消息通知其他中心
        StopWatchUtils.start("订单同步批量关闭", "sendSalesOrderChangeMsg");
        List<String> salesOrderNos = orderIdsMap.values().stream().flatMap(List::stream).collect(Collectors.toList());
        sendMsgService.sendSalesOrderChangeMsg(salesOrderNos, InnerMessageEventEnum.SALES_ORDER_CANCELED);
        StopWatchUtils.stop();

        // 发送MQ消息释放活动预占
        StopWatchUtils.start("订单同步批量关闭", "sendMessage");
        try {
            log.info("AbstractOrderAtomCancelService#batchCancel forecastOrderLineIdsMap={}", JSON.toJSONString(forecastOrderLineIdsMap));
            forecastOrderLineIdsMap.forEach((sequenceNo, forecastOrderLineIds) -> {
                if (StringUtils.isBlank(sequenceNo) || CollectionUtils.isEmpty(forecastOrderLineIds)) {
                    return;
                }
                sendMsgService.sendActivityFailMsg(sequenceNo, forecastOrderLineIds.stream().map(Long::valueOf).collect(Collectors.toList()));
            });
        } catch (Exception e) {
            log.error("AbstractOrderAtomCancelService#batchCancel sendActivityFailMsg error", e);
        }
        StopWatchUtils.stop();

        log.info("AbstractOrderAtomCancelService#batchCancel stopWatch.prettyPrint()={}", stopWatch.prettyPrint());
        log.info("AbstractOrderAtomCancelService#batchCancel stopWatch.getTotalTimeSeconds()={}", stopWatch.getTotalTimeSeconds());
        return responseList;
    }

    private void preHandleRequestParams(OrderAtomBatchCancelRequest request, String orderCategory) {
        if (CollectionUtils.isEmpty(request.getOrderList())) {
            return;
        }
        request.getOrderList().forEach(order -> {
            if (StringUtils.isNotBlank(request.getFromSys())) {
                order.setFromSys(request.getFromSys());
            }
            if (StringUtils.isNotBlank(request.getBusinessType())) {
                order.setBusinessType(request.getBusinessType());
            }
            if (StringUtils.isNotBlank(request.getBusinessUnitCode())) {
                order.setBusinessUnitCode(request.getBusinessUnitCode());
            }
            if (StringUtils.isNotBlank(request.getModifierCode())) {
                order.setModifierCode(request.getModifierCode());
            }
        });
    }

    private void paramsInvalidCheck(OrderAtomBatchCancelRequest request, String orderCategory) {
        AssertUtils.isTrue(CollectionUtils.isEmpty(request.getOrderList()), "OC-01-001-01-15-001", "单据列表");
        AssertUtils.isTrue(request.getOrderList().size() > 100, "OC-01-001-01-15-004", "单据列表", request.getOrderList().size(), "100");

        Set<String> orderSet = new HashSet<>();
        request.getOrderList().forEach(order -> {
            String orderKey = order.getSalesOrderNo();
            if (orderSet.contains(orderKey)) {
                throw new FunctionException("OC-01-001-01-15-002", "订单单号", orderKey);
            }
            orderSet.add(orderKey);

            // 必填校验
            AssertUtils.isTrue(StringUtils.isBlank(order.getFromSys()), "OC-01-001-01-15-001", "来源系统编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getBusinessType()), "OC-01-001-01-15-001", "业态编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getBusinessUnitCode()), "OC-01-001-01-15-001", "业务单元编码");
            AssertUtils.isTrue(StringUtils.isBlank(order.getSalesOrderNo()), "OC-01-001-01-15-001", "销售订单单号");
            AssertUtils.isTrue(StringUtils.isBlank(order.getModifierCode()), "OC-01-001-01-15-001", "修改人工号");
//            AssertUtils.isTrue(StringUtils.isBlank(order.getSalesOrderNo()), "OC-01-001-01-15-001", "订单单号");
            if (OrderCategoryEnum.COMPANY.getCode().equals(orderCategory)) {
                AssertUtils.isTrue(StringUtils.isBlank(order.getModifierName()), "OC-01-001-01-15-001", "修改人姓名");
            }

            //长度校验
            AssertUtils.lengthCheck(order.getFromSys(), 50, true, "OC-01-001-01-15-004", "来源系统编码");
            AssertUtils.lengthCheck(order.getBusinessType(), 10, true, "OC-01-001-01-15-004", "业态编码");
            AssertUtils.lengthCheck(order.getBusinessUnitCode(), 50, true, "OC-01-001-01-15-004", "业务单元编码");
            AssertUtils.lengthCheck(order.getSalesOrderNo(), 50, true, "OC-01-001-01-15-004", "销售订单单号");
            AssertUtils.lengthCheck(order.getModifierCode(), 50, true, "OC-01-001-01-15-004", "修改人工号");
//            AssertUtils.lengthCheck(order.getSalesOrderNo(), 50, true, "OC-01-001-01-15-004", "订单单号");
            AssertUtils.isNumber(order.getBusinessType(), true, "OC-01-001-01-15-006", "业态编码");
            AssertUtils.lengthCheck(order.getCancelCode(), 50, false, "OC-01-001-01-15-004", "取消原因编码");
            if (OrderCategoryEnum.COMPANY.getCode().equals(orderCategory)) {
                AssertUtils.lengthCheck(order.getModifierName(), 50, true, "OC-01-001-01-15-004", "修改人姓名");
            }

            //枚举校验
            if (StringUtils.isNotBlank(order.getCancelCode())) {
                SalesOrderCloseEnum salesOrderCloseEnum = SalesOrderCloseEnum.of(order.getCancelCode());
                Optional.ofNullable(salesOrderCloseEnum).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "取消原因编码"));
            }
        });

        // 字典值校验
        dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.FROM_SYS.getCode(), request.getFromSys(),new FunctionException("OC-01-001-01-15-006", "来源系统编码"));
        dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.BUSINESS_TYPE.getCode(), request.getBusinessType(), new FunctionException("OC-01-001-01-15-006", "业态编码"));
        AssertUtils.isTrue(!businessUnitAbilityAdapter.checkBusinessUnitCode(request.getBusinessUnitCode()), "OC-01-001-01-15-006", "业务单元编码");
    }

    private void assembleBizBaseInfo(OrderAtomBatchCancelRequest request, String orderCategory) {
        // 初始化修改人名称，并校验员工号是否存在
        List<String> modifierCodes = request.getOrderList().stream()
                .filter(o -> StringUtils.isBlank(o.getModifierName()))
                .map(OrderAtomCancelRequest::getModifierCode)
                .collect(Collectors.toList());
        Map<String, Modifiers> modifierMap = commonCheck.invalidModifierList(modifierCodes);
        request.getOrderList().forEach(order -> {
            if (StringUtils.isBlank(order.getModifierName()) && modifierMap.containsKey(order.getModifierCode())) {
                order.setModifierName(modifierMap.get(order.getModifierCode()).getName());
            }
        });
    }

    private List<OrderSDO> querySalesOrder(OrderAtomBatchCancelRequest request, List<OrderAtomCancelResponse> responseList, Boolean needLines) {
        // 查询订单信息
        QueryByOrderBizIdsRequest queryByOrderBizIdsRequest = QueryByOrderBizIdsRequest.builder()
                .fromSys(request.getFromSys())
                .businessType(Integer.valueOf(request.getBusinessType()))
                .businessUnitOutCode(request.getBusinessUnitCode())
                .orderBizIds(request.getOrderList().stream().map(OrderAtomCancelRequest::getSalesOrderNo).collect(Collectors.toList()))
                .build();
        List<OrderSDO> orderSDOS = orderQueryServiceRepository.queryByOrderBizIds(queryByOrderBizIdsRequest, needLines);

        List<String> dbSalesOrders = orderSDOS.stream().map(orderSDO -> String.format("%s_%s_%s_%s", orderSDO.getFromSys(), orderSDO.getBusinessType(), orderSDO.getBusinessUnitOutCode(), orderSDO.getOrderBizId())).collect(Collectors.toList());
        // 校验改成合并校验【系统来源编码+业态编码+业务单元编码+中台销售单号】
        List<String> noExistSalesOrders = request.getOrderList().stream()
                .map(order -> String.format("%s_%s_%s_%s", request.getFromSys(), request.getBusinessType(), request.getBusinessUnitCode(), order.getSalesOrderNo()))
                .filter(salesOrderNo -> !dbSalesOrders.contains(salesOrderNo))
                .distinct()
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(noExistSalesOrders)) {
            for (String x : noExistSalesOrders) {
                OrderAtomCancelResponse response = new OrderAtomCancelResponse();
                String salesOrderNo = x.substring(x.lastIndexOf("_") + 1);
                response.setSalesOrderNo(salesOrderNo);
                response.setErrorCode(getOrderTagNameForErrorMsg());
                response.setMessage(ErrorMessage.code(getOrderTagNameForErrorMsg(), "").getDisplayErrorMessage());
                responseList.add(response);
            }
        }

        List<OrderSDO> orderSDOList = new ArrayList<>();
        for (OrderSDO orderSDO : orderSDOS) {
            // 过滤非本接口类型的订单，防止串用
            switch (getOrderTag()) {
                case "exchange":
                    if (!"exchange".equals(orderSDO.getOrderTag())) {
//                        throw new FunctionException("OC-03-001-01-15-008", orderSDO.getOrderBizId());
                        OrderAtomCancelResponse response = new OrderAtomCancelResponse();
                        response.setSalesOrderNo(orderSDO.getOrderBizId());
                        response.setErrorCode(getOrderTagNameForErrorMsg());
                        response.setMessage(ErrorMessage.code(getOrderTagNameForErrorMsg(), "").getDisplayErrorMessage());
                        responseList.add(response);
                    } else {
                        orderSDOList.add(orderSDO);
                    }
                    break;
                case "normal":
                    if (!"normal".equals(orderSDO.getOrderTag())) {
//                        throw new FunctionException("OC-01-001-01-16-016", orderSDO.getOrderBizId());
                        OrderAtomCancelResponse response = new OrderAtomCancelResponse();
                        response.setSalesOrderNo(orderSDO.getOrderBizId());
                        response.setErrorCode(getOrderTagNameForErrorMsg());
                        response.setMessage(ErrorMessage.code(getOrderTagNameForErrorMsg(), "").getDisplayErrorMessage());
                        responseList.add(response);
                    } else {
                        orderSDOList.add(orderSDO);
                    }
                    break;
                case "return":
                    if (!"return".equals(orderSDO.getOrderTag())) {
//                        throw new FunctionException("OC-02-001-01-15-008", orderSDO.getOrderBizId());
                        OrderAtomCancelResponse response = new OrderAtomCancelResponse();
                        response.setSalesOrderNo(orderSDO.getOrderBizId());
                        response.setErrorCode(getOrderTagNameForErrorMsg());
                        response.setMessage(ErrorMessage.code(getOrderTagNameForErrorMsg(), "").getDisplayErrorMessage());
                        responseList.add(response);
                    } else {
                        orderSDOList.add(orderSDO);
                    }
                    break;
            }
        }
        return orderSDOList;
    }
}
